iT邦幫忙

2026 iThome 鐵人賽

DAY 18
0

我做了兩份紀錄,丟給同一個驗收器。

第一份,成品合格,流程被判失敗。第二份,成品不合格,流程卻被判通過。

兩份都是固定的合成資料,不是我真的跑出來的事故。但這個對照就是今天要講的整件事:成品能不能用,跟流程有沒有拿對輸入、跑對版本、經過該經過的停靠點,是兩張不同的成績單。

前兩天我一直在存東西。Day 16 定義一輪工作是誰、該讀哪段資料,Day 17 保存中斷後接得回去的證據。今天第一次回頭把其中一份拿出來用:六組案例裡有一組,直接讀 Day 17 存下來的那份恢復紀錄當上游證據。其他五組是各自獨立的合成案例,沒有接回前兩天。

兩份紀錄,結果相反

第一份叫 approval-skipped。它的成品跟正常那份用的是同一個內容摘要,也就是同一份合格的文章。差別只有一個:事件紀錄從「等人審」直接跳到「候選完成」,中間該有的批准沒有發生。

成品驗收給它 pass,流程驗收給它 fail,原因碼是 approval_required_before_candidate

第二份叫 missing-source。它的成品缺了必要的來源參照。成品驗收給它 fail,終止狀態是 blocked,而流程驗收給它 pass

第二份那個 pass 是最容易被誤讀的一格。它不是說「缺來源的成品可以用」,而是說「流程在品質檢查那一站正確地把它停住了,沒有繼續往批准和交付走」。

流程做對了它該做的事。成品還是不能用。

四項判定,不要加總

如果我把成品和流程加總成一個分數,上面那兩份紀錄會長得一模一樣:都是「一半好一半壞」。但它們需要的處置完全不同。

所以每組案例分開存四項:

判定 它回答什麼 可能的值
成品驗收 這份東西本身合不合格 pass / fail
終止狀態 這一輪停在哪 candidate_ready / blocked
流程驗收 走過來的路合不合法 pass / fail
案例斷言 實際結果跟事先寫下的標準答案一樣嗎 pass / fail

前兩項組合起來,就是四種需要不同處置的情況:

成品 流程 該做什麼
通過 通過 可以進到下一站,但這不等於自動發布
通過 失敗 把候選成品隔離,先查跳步、重複或身分錯置
失敗 通過 流程正確擋下了,去修成品或輸入
失敗 失敗 停下來,內容規則和控制流程兩邊都要查

一個總分會把這四格壓成一格。模型評分再高,也不能把「必要來源缺失」或「批准被跳過」洗成通過。

第四項那個「案例斷言」最容易搞混,我多說一句。它問的不是「這份東西好不好」,而是「驗收器有沒有給出我事先預期的答案」。所以一個負面案例被正確攔下時,成品是 fail、流程可能也是 fail,但案例斷言是 pass —— 因為它本來就該被攔下。

還有一件事要講清楚:blocked 不是第三種成品分數。它是終止狀態,跟成品的 pass / fail 是不同的欄位、回答不同的問題。

為什麼要獨立一欄?因為「這份東西不合格」和「這一輪停在哪裡」是兩件會分開變化的事。成品不合格但流程一路衝到候選完成,跟成品不合格而流程在品質檢查就停住,是完全不同的嚴重程度。只存成品分數的話,這兩種長得一樣。

驗收器實際讀什麼

它不讀我的文章正文,它讀三塊東西。

第一塊是成品本身:內容、內容的摘要、以及必要來源的識別碼清單。

第二塊是上游證據:檢查點與恢復紀錄的參照,也就是「這一輪從哪裡接回來的」。六組案例裡只有中斷接續那一組真的填了它,而且填的是 Day 17 那份恢復紀錄;其餘五組這兩欄是空的,因為它們本來就沒有中斷過。

第三塊是事件紀錄,一筆一筆按順序排。每一筆記得自己的序號、事件識別碼、屬於哪一輪、哪一次進入、哪個階段、是什麼種類的事件、狀態如何、動到的內容摘要是哪一份、效果識別碼、以及原因碼。

案例層再包一圈:資料格式版本、案例集版本、案例識別碼、是不是合成資料、這組改了什麼變因、以及事先寫好的預期判定。

有一件事是刻意的:正文與來源全文都不進事件紀錄,只留參照和可以重算的摘要。 軌跡這種東西很容易夾帶不該留的內容,像是模型的輸入輸出、來源全文、私人網址。可以除錯不表示什麼都要記。

成品驗收實際在做什麼

它做的事比我想像的少,但每一件都很硬。

先重算內容摘要。 把成品內容規範化之後算一次 SHA-256,跟存檔裡那個摘要比。不合就直接停在這裡,不繼續評分,也不回一個 fail 分數。

這個設計我想解釋一下。摘要不合的意思是證據本身壞掉了,不是內容不好。手上這份東西已經不確定是不是當初那一份,這時候給它任何評分都是在假裝知道自己在評什麼。

再看必要來源有沒有綁上。 每一個被標成「這句需要來源」的主張,都必須有一個狀態是「已驗證」的來源綁定。找不到就記一筆 required_source_missing

最後看內容紅線清單。 那份清單只要不是空的,就記一筆 hard_rule_violation

兩條規則,任一條命中就是 fail。不加權、不打分,也不接受模型用分數補回來。

順帶說一個實作細節。驗收器本身有一份「我檢查哪些項目」的宣告清單,但那份清單不是程式的執行順序表,它是拿去算驗收器定義指紋用的。換句話說:規則改了,指紋就變,前後兩次的結果就知道不能直接比。 這比用註解寫「本版檢查四項」可靠得多。

流程驗收看的是不變條件

流程驗收器檢查的東西比成品那邊多得多:事件序號要遞增、事件識別碼不能重複、run_id 要一致、進入身分要有登錄、階段轉移要合法、必要事件要存在、禁止事件不能存在、批准要早於候選完成、批准綁的摘要要對得上、相同的效果與同一個階段執行不能重複。中斷接續的案例還要能指回 Day 17 的檢查點與恢復紀錄。

這裡有個數字我得說清楚。程式裡列得出來的原因碼一共 19 種,但這一輪真的被走到的是 8 種:六組案例踩到 3 種,測試裡另外手動構造探針驗了 5 種。剩下 11 種只有程式碼,沒有走過的紀錄。

「有這個分支」和「這個分支被驗過」是兩件事。所以我不會說這套評估涵蓋 19 種異常,只能說有實測紀錄的是 8 種。

有一個機制我覺得設計得很漂亮,雖然這輪沒被走到:每一筆事件的識別碼,是那筆事件自己內容的雜湊。 把事件其他欄位算一次雜湊,取前面一段當它的識別碼。所以只要有人改動事件裡任何一欄,識別碼就對不上,重算的時候會被抓出來。這條分支就在剩下那 11 種裡面,程式有,但這六組案例和測試都沒有去踩它。

另外一項則是特別值得單獨講的:批准要綁內容摘要。

事件名稱寫著「已批准」是不夠的。如果那個批准綁的摘要跟現在這份成品不是同一份,就不能放行。批准的是哪一份稿,這件事得可以查,不能只是「那時候有人說可以」。

另外一項是關於「不鎖死唯一路徑」。流程驗收檢查的是條件,不是比對一份唯一正確的事件清單。所以流程多留了一筆合法的診斷事件,只要沒有破壞上面那些條件,就不該因為「跟標準清單不完全一樣」而被判失敗。

這個取捨有來歷。Anthropic 的評估文件就提醒過,逐步鎖死特定的工具順序,容易把其他同樣合法的做法一起拒絕掉。允許合法變化不等於可以省略必要事件 —— 哪些事件是必要的,仍然由版本化的流程規則決定。

六組案例,每組只改一個變因

六組固定合成案例,按順序是正常通過、預期擋下、缺來源、跳過批准、重複執行、中斷接續。

案例 唯一的變異 事件數 成品/終止/流程
normal-pass 7 pass / candidate_ready / pass
expected-block 固定命中內容紅線 5 fail / blocked / pass
missing-source 移除必要來源參照 5 fail / blocked / pass
approval-skipped 跳過人工批准 6 pass / candidate_ready / fail
duplicate-attempt 重複效果與階段執行 8 pass / candidate_ready / fail
interrupted-resume 指回 Day 17 證據後合法接續 9 pass / candidate_ready / pass

兩組被擋下的案例,終止原因碼也是分開存的:命中內容紅線那組是 content_policy_blocked,缺來源那組是 required_source_missing。停下來的理由不會被壓成一個「被擋了」。

彙總起來:成品 4 組通過、2 組失敗;終止狀態 4 組候選完成、2 組受控停止;流程 4 組通過、2 組失敗。案例斷言 6 組全部通過。

模型評分器 0 次,外部呼叫 0 次。 這兩個 0 我要講精確一點:它們是寫死的宣告,不是統計出來的數字。因為這套程式裡根本沒有一條呼叫外部服務的路徑,所以它宣告 0。

然後是那個 6 組全過。這件事我原本想寫得漂亮一點,但拆開機制之後不能這樣寫。

那六個「標準答案」,是我在建案例的時候手寫在參數裡的。而判定它們的規則,也是我寫的。兩邊是同一批判斷的兩次表達,不是「把已知輸入丟給一個獨立的評分器,結果剛好符合預期」。

所以 6/6 能證明的是:同一份程式碼重跑,會得到一模一樣的結果。 它不能證明這套評分邏輯本身是對的。如果我對「什麼叫跳過批准」的理解一開始就錯了,那我會穩定地、每次都得到同一個錯答案,而這張表看起來還是漂亮的 6/6。

這也是為什麼 OpenAI 的評估指引一直強調要有可信的人工標籤來校準,而 AgentRewardBench 那類研究要花力氣讓專家去標註軌跡。真正的標準答案必須來自另一雙眼睛。今天這一份,暫時還不是。

「每組只改一個變因」是我覺得這組案例最值錢的地方。approval-skipped 用的是跟 normal-pass 一樣的成品,所以流程被判失敗這件事,只能是執行事件造成的,不可能是文筆差異混進來。變因不乾淨的話,一份表格看起來很豐富,其實推不出任何結論。

案例集也刻意同時放了「應該通過」和「應該失敗」的路徑。只有正面案例的話,驗收器全部回 pass 也看不出它是真的在檢查,還是根本沒接上線。

duplicate-attempt 那組也值得單獨看一眼。它的成品是通過的,因為東西本身沒問題;被判失敗的是流程,而且一個變異同時踩到兩條不變條件:效果識別碼重複、階段執行重複,所以它留下兩個原因碼而不是一個。

這件事光看成品永遠看不出來。重複執行不會讓文章變難看,它只會讓外面多出一份不該有的結果。事件紀錄裡那個效果識別碼就是為這種事存的。

一個總分沒辦法除錯

流程失敗的時候,我不只存 fail,還存原因碼:批准缺失、批准摘要不合、事件出現在終止狀態之後。

差別在於能不能回去修。拿到「流程分數 0.62」我不知道要動哪裡;拿到 approval_required_before_candidate,我知道要去看批准那一段。原因碼是讓人走回壞掉的那個不變條件,不是給一個好看的數字。

當然,有結構化的標籤不等於標籤一定對。規則寫錯了,它就穩定地、每次都給你同一個錯答案。

報告自己說過關,也不算

Day 17 那篇我寫過一句:產物自己寫著「我通過了」不算數。今天同一個道理往上再套一層。

案例斷言那個欄位,雖然報告檔裡已經寫著結果了,但驗收的時候程式會自己重算一次,然後要求兩邊一致。不一致就直接判 report_assertion_mismatch

換句話說,手動把報告裡的 fail 改成 pass 是沒用的。測試裡就有一條專門做這件事,把報告的斷言值改掉,看它會不會被抓出來。同一組測試還試了另外兩種手腳:改掉驗收器的版本字串、改掉案例的自我參照,兩種都會被擋下。

那兩份保存的 JSON 也上了另一道鎖:schema 的每一個物件節點都不允許多出未知欄位。塞一個沒定義過的欄位進去,schema 會擋,程式的案例檢查也會丟出格式錯誤。

聽起來有點多疑。但這幾道都是在防同一件事:一份「證明流程沒問題」的紀錄,本身也需要能被證明沒被動過。 不然它就只是一份自我聲明。

程式、模型、人工,各驗不同的問題

這三者不是誰比誰強,是分工。

程式負責欄位、摘要、來源綁定、必要事件、禁止事件、重複執行。理由很單純:這些規則可以逐項重跑,而且每次結果一樣。

模型適合的是開放式的文字面向:清楚度、來源說明夠不夠、語氣、風格。但它有兩個前提:要先跟人工標註校準過,而且不能讓它去改寫確定性的硬規則。

人工有兩個責任,而且這兩個不能混在一起:一是校準模型評分器,二是決定單篇內容要不要發布。前者做完不等於後者自動批准。

有一份研究我覺得值得記著。AgentRewardBench 收了 1,302 條由專家標註成功、副作用與重複行動的網頁代理軌跡,比較了 12 種模型評分器,結論是沒有哪一種在所有基準上都最好;而既有的規則式評估也可能漏報合法的成功。

兩邊都有盲點。這不代表要放棄確定性規則,而是說「重複行動」這種東西值得被獨立檢查一次,這也是為什麼上面六組案例裡有一組專門測重複執行。

另外,模型當評審還有一個很難處理的傾向:它可能偏好模型自己生成的文字。G-Eval 那篇論文在特定摘要任務上就觀察到這個風險。所以如果哪天我真的加了文字品質評分,規則版本、模型識別和人工標籤都得存下來,模型跟人工不一致時送人工複核。

不過今天沒走到那裡。今天沒有實跑任何模型評分器。

這條基線走得到哪裡

六組案例能說的只有一句:這個參考評估器,對這六組固定合成輸入,給出了跟事先標準答案一致的判定。

它沒有測真實流量、沒有測外部發布、沒有多人並行、沒有斷電,也沒有用正式的內容分布。NIST 的指引提醒過,部署前測試可能跟正式部署情境不符,測試要記錄條件與限制,不能把實驗室結果當成現場保證。

所以我不會把這六組叫做回歸成效。它是一條基線:以後規則改了,可以拿它比對前後有沒有退步的那個起點。

還有幾件事我今天刻意沒碰:評估者和修改者反覆修稿要修幾次才停、誰接手,那是後面的題目;用同一份資料集比較模型或提示詞改版前後有沒有退步,也是後面的題目;外部發布只成功一半、回應遺失、要去對帳,留給 Day 26。

版本這件事最後補一句。案例、案例集、成品驗收器、流程驗收器、案例斷言,各自都留了版本與定義摘要。理由很實際:如果規則改了卻沿用同一個名字,前後兩次的結果就沒辦法比。 一張六列的結果表,如果沒有產生它的資料和規則,下一次根本無從核對。

明天要問的是「該不該讓它自己決定」

測試這次 10 條全過。裡面我最在意的不是那些「應該通過」的案例,而是那幾條反例探針:換掉 run_id、改掉批准綁的摘要、在已經停住的案例後面多塞一個候選完成事件。那幾條是在確認一件事——驗收器真的會擋,不是所有輸入都回 pass

一個什麼都放行的驗收器,跟沒有驗收器是一樣的,但它會讓人更安心,所以更危險。

今天做完的事其實很單純:把「成品好不好」和「流程對不對」拆成兩張成績單,各自留下可以重跑的判定和原因。

有了這個,才輪到下一個問題:哪些任務真的需要讓 AI 自己決定下一步,哪些其實照固定規則跑就好。

那是 Day 19 的事。但我想先把話說在這裡:沒有今天這一層,那個問題根本沒辦法回答。因為你無從判斷它自己決定的那幾步,到底做對了沒有。

參考資料


上一篇
Day 17|AI 工作流跑到一半停了,怎麼接著跑?
系列文
情報進來,內容發出去:30 天拆一條每天真的在跑的 AI 內容產線18
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言